package edu.mercer.sse.bkp;

import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashSet;
import java.util.Set;

import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;

import static com.google.common.base.Preconditions.checkArgument;

/**
 * Obtain collection of file paths for a directory.<p>
 *
 */

public class FolderContents 
{
	/** 
	 * Path of directory used to recursively obtain all file Paths, 
	 * 	subdirectory files' Paths.<p> 
	 */
	
	Optional<Path> _directory = Optional.absent();
	
	
	/**
	 * FolderContents constructor.<p>
	 * 
	 * @param dirIn - Path of directory used to recursively obtain all file 
	 * 	Paths, subdirectory files' Paths
	 * 
	 * @throws IOException  Path unreadable or not a directory
	 */
	
	private FolderContents( final Path dirIn ) throws IOException
	{
		checkArgument( dirIn.toFile()
							.canRead(), "unreadble path" );

		checkArgument( dirIn.toFile()
							.isDirectory(), "directory expected" );
		
		_directory = Optional.of( dirIn );
		
	}//constructor


	/**
	 * Factory: FolderContents.<p>
	 * 
	 * @param directory - Path of directory used to recursively obtain all 
	 * 	file Paths, subdirectory files' Paths
	 * 
	 * @return  this
	 * 
	 * @throws IOException  Directory Path argument unreadable or not a 
	 * 	directory
	 */
	
	public static FolderContents factory( final Path directory ) throws 
			IOException
	{
		return new FolderContents( directory );
		
	}//method


	/** 
	 * @return ImmutableSet&#60;Path&#62; - recursive list of files: 
	 * collection of file paths for directory 
	 * 
	 * @throws IOException 
	 */

	public ImmutableSet<Path> fileSet() throws IOException
	{
		FileSystemWalker fsoWalker = FileSystemWalker.factory();
		
		Files.walkFileTree( _directory.get(), fsoWalker );
		
		return fsoWalker.filesFound(); 
		
	}//method
	
	
}//class


/**
 * Collection of Paths passing criteria.<p>
 * 
 * Evaluates file, directory Paths and adds them to a Paths collection.<p>
 * 
 * Predicate-like, serves as filter. Evaluates file system Paths, gathering 
 * only readable file Paths, omitting Directory Paths.<p>
 * 
 * @see 
 * <a href="http://docs.oracle.com/javase/7/docs/api/java/nio/file/SimpleFileVisitor.html">
 * SimpleFileVisitor</a>
 */

class FileSystemWalker extends SimpleFileVisitor<Path>
{
	/** 
	 * unique list of recursive list of files: collection of file paths for 
	 * directory 
	 */

	private Set<Path> _filesFound = new HashSet<>();
	
	
	private FileSystemWalker()
	{
		super();
		
	}//constructor

	
	private FileSystemWalker( final Set<Path> filesFound )
	{
		super();
		
		_filesFound = filesFound;
		
	}//constructor
	
	
	public static FileSystemWalker factory( final Path directory, 
											final Set<Path> filesFound )
	{
		return new FileSystemWalker( filesFound );
		
	}//method

	
	public static FileSystemWalker factory()
	{		
		return new FileSystemWalker();
		
	}//method
	
	
	public ImmutableSet<Path> filesFound()
	{ 
		return ImmutableSet.copyOf( _filesFound ); 
	
	}//method

	
	@Override 
	public FileVisitResult visitFile( final Path fileIn, 
									  final BasicFileAttributes attrs )
		throws IOException 
	{
		if( fileIn.toFile()
				  .isFile() &&
			fileIn.toFile()
				  .canRead() )
		{
			_filesFound.add( fileIn );
			
		}//if
		
		return FileVisitResult.CONTINUE;
		
	}//method

	
	@Override  
	public FileVisitResult preVisitDirectory( final	Path dirIn, 
											  final BasicFileAttributes 
											  		attrs )
		throws IOException 
	{
		return FileVisitResult.CONTINUE;
		
	}//method

	
}//class

